import { Modal } from "antd";
import db, { IDownloadDBFile, IDownloadDBTask, IHistory } from "model/DB";
import moment from "moment";
import { useEffect, useRef, useState } from "react"
import { TaskStatus, TSStatus } from "renderer/constants/Consts";
import GlobalContext, { IConfig, IDownloadTaskMap, IUser } from "renderer/contexts/GlobalContext"

moment.locale('zh')


interface GlobaleProps {
  user: IUser
}

// 最多只显示 10 个播放记录
const PlayCount = 10

// 最多开启 5 个m3u8下载任务
// 每个m3u8下载任务最多同时下载5个ts

/** 下载任务数 */
let taskCount: number = 0;
const MaxCount = 3

// 正在下载任务数据 内存数据，便于多任务下载时不进行重复下载
const TaskMap: IDownloadTaskMap = {}

// 每个任务的 ts 下载数
type TaskTsCountType = {
  [key in number]: number
}
const TaskTsCount: TaskTsCountType = {}
const addTaskTsCount = (taskId: number) => {
  if(Object.prototype.hasOwnProperty.call(TaskTsCount, taskId)) {
    TaskTsCount[taskId] = TaskTsCount[taskId] + 1
  } else {
    TaskTsCount[taskId] = 1
  }
}
const reduceTaskTsCount = (taskId: number) => {
  if(Object.prototype.hasOwnProperty.call(TaskTsCount, taskId)) {
    TaskTsCount[taskId] = TaskTsCount[taskId] - 1
  } else {
    TaskTsCount[taskId] = 0
  }
}

const GlobalProvider: React.FC<GlobaleProps> = (props) => {

  const [ user, setUser ] = useState<IUser>(props.user)

  const [ config, setConfig ] = useState<IConfig>({
    port: 38192
  })

  const [ taskList, setTaskList ] = useState<IDownloadDBTask[]>([])

  const [ playTask, setPlayTask ] = useState<IHistory>()
  const [ playHistory, setPlayHistory ] = useState<IHistory[]>([])

  const playTaskRef = useRef(playTask)

  const setUserInfo = (value: IUser) => {
    setUser(value)

    // 缓存本地user-info
    window.electron.ipcRenderer.setStoreValue('user-info', value)
  }

  // 播放课程
  const playCourse = async (task: IHistory) => {

    if(playTask && playTask.taskId === task.taskId) {
      // 同一个任务时，不更新播放， 如果当前页不在播放页，跳转到该页
      return 
    } 

    // 更新播放
    setPlayTask(task)
    playTaskRef.current = task

    const dbPlay = await db.historyList.where('taskId').equals(task.taskId).first()

    let newTask = {...dbPlay, ...task}

    window.electron.log.info('play task: ', JSON.stringify(newTask))

    // const playDate = moment().format('YYYY-MM-DD hh:mm:ss')

    // 如果存在该历史
    if(dbPlay) {
      // 更新数据
      db.historyList.where({taskId: task.taskId}).modify(newTask)
      
    } else {
      // 不存在，新增一条记录
      const historyId = await db.historyList.add({...task})

      newTask.id = historyId
      // setPlayHistory(old => {
      //   // 判断播放历史是否存在该数据，如果存在，就更新
      //   old.push({...task, playDate: task.playDate, id: historyId, })
      //   return [...old]
      // })
    }

    // 更新播放列表
    setPlayHistory(old => {
      // 判断播放历史是否存在该数据，如果存在，就更新
      const hasIdx = old.findIndex(item => item.taskId === task.taskId)
      // console.log('hasIdx =', hasIdx, old, task)
      if(hasIdx !== -1) {
        old.forEach(item => {
          if(item.taskId === task.taskId) {
            item.playDate = task.playDate
          }
        })

        return [...old]
        
      } else {
        if(old.length >= PlayCount) {
          // 移除并添加, 按照 playDate 排序，删除日期最小的
          old.unshift({...newTask})
          old.sort((a, b) => a.playDate > b.playDate ? -1 : 1)

          return old.filter((_, idx) => idx < PlayCount)
        } else {
          // 直接新增
          old.unshift({...newTask})

          return [...old]
        }
      }
      
    })

  }

  // 更新播放课程
  const updateCourse = async (task: IHistory | undefined) => {
    setPlayTask(task)
    playTaskRef.current = task
  }

  // 删除课程
  const deleteCourse = async (task: IDownloadDBTask) => {
    const { id, path } = task!

    // 判断删除的任务是否 TaskMap 中的任务
    if(TaskMap[id!]) {
      delete TaskMap[id!]
    }

    // 删除数据库数据
    // 删除 taks 表
    await db.downloadTasks.delete(id!)
    // 删除 file 表
    db.downloadFiles.where('taskId').equals(id!).delete()
    // 删除 history 表
    db.historyList.where('taskId').equals(id!).delete()

    // 删除目录及文件
    window.electron.ipcRenderer.deleteM3U8(path.substring(0, path.lastIndexOf('\\')))

    queryHistory()

    // 更新渲染数据
    // console.log('taskList =', taskList, id)
    setTaskList(old => old.filter(item => item.id !== id))

    return Promise.resolve(true)
  }

  // 添加 m3u8 任务
  const addTask = (task: IDownloadDBTask, files: IDownloadDBFile[]) => {
    if(task.id === undefined ) {
      return
    }
    // 判断当前是否可以开启下载，比较正在进行中的任务个数
    if(taskCount < 1) {
      taskCount = taskCount + 1;
      // 更新数据库状态 
      db.downloadTasks.put({
        ...task,
        status: TaskStatus.Downloading
      })
      
      // 开启ts下载 第一次默认开启 3 个下载
      const newFiles = files.map((file, index) => {
        if(index < MaxCount) {
          addTaskTsCount(task.id!)

          // 开启 ts 下载
          window.electron.ipcRenderer.startDownloadTS({
            url: file.url,
            filePath: file.path,
            taskId: task.id!,
            // 一个m3u8中，ts文件名具有唯一性
            name: file.name
          })
          
          //  数据库不保持 ts 文件下载中的状态
          // db.downloadFiles.where({taskId: task.id!, name: file.name}).modify({status: TSStatus.Downloading})

          return {...file, status: TSStatus.Downloading}
        } else {
          return {...file}
        }
      })

      TaskMap[task.id!] = {
        ...task,
        files: newFiles,
        status: TaskStatus.Downloading
      }

      // 更新渲染数据
      setTaskList(old => {
        old.push({...task, status: TaskStatus.Downloading})
        return [...old]
      })
     
    }
  }
  // 暂停 m3u8 任务
  const pauseTask = async (task: IDownloadDBTask) => {
    if(task.id === undefined ) {
      return Promise.resolve(false)
    }

    // 判断当前任务是否正在下载中，
    if(TaskMap[task.id]) {
      const taskData = TaskMap[task.id]
      const { status } = taskData
      taskData.status = TaskStatus.Pause

      // 更新渲染数据
      setTaskList(old => old.filter(item => item.id !== task.id))

      if(status === TaskStatus.Downloading) {
        // 开启新的下载任务
        taskCount = taskCount - 1;
        // 查找第一个待下载的任务，开启下载
        const newTask = await db.downloadTasks.where('status').equals(TaskStatus.Waiting).first()
        if(newTask) {
          const newFiles = await db.downloadFiles.where({taskId: newTask.id!})
                                .and(function(account){
                                  return account.status !== TSStatus.Done
                                })
                                .toArray()
          // console.log('files ==', files)
          addTask(newTask, newFiles)
        }
      }
      
    }

    // 更新数据库
    const result = await db.downloadTasks.put({
      ...task,
      status: TaskStatus.Pause
    })

    return Promise.resolve(true)
    
  }
  // 恢复 m3u8 下载任务
  const resumeTask = async (task: IDownloadDBTask) => {
    if(task.id === undefined) {
      return Promise.resolve(false)
    }

    let status = task.status

    if(taskCount > 0) {
      status = TaskStatus.Waiting
      // 已有任务在下载，当前任务只能变更为待下载状态
      if(TaskMap[task.id]) {
        const taskData = TaskMap[task.id]
        taskData.status = status
      }
      
    } else {
      // 开启新的下载任务
      status = TaskStatus.Downloading
      // 查找第一个待下载的任务，开启下载
      const newFiles = await db.downloadFiles.where({taskId: task.id!})
                            .and(function(account){
                              return account.status !== TSStatus.Done
                            })
                            .toArray()
      // console.log('files ==', files)
      addTask(task, newFiles)
    }

    

    // 更新数据库
    const result = await db.downloadTasks.put({
      ...task,
      status,
    })

    return Promise.resolve(true)

  }

  // 查询播放list
  const queryHistory = async () => {
    // 查询播放历史
    const list = await db.historyList.orderBy('playDate').reverse().limit(PlayCount).toArray()

    setPlayHistory(list)
  }


  // 监听主进程ts文件下载完成
  useEffect(() => {

    const downloadTS = async (files: IDownloadDBFile[], taskId: number) => {
      // 判断 待下载状态的 ts 文件是否已下载完，如果是，则开启状态为 error ts文件，进行重复下载
      const hasWaiting = files.find(file => file.status === TSStatus.Waiting)

      // console.log('files =', files)

      for(let i = 0; i < files.length; i++) {
        const file = files[i]
        // todo 当待下载的 ts 已全部下载完成时，不进行状态为error ts文件的重复下载，直接提示下载失败
        // 用户手动开启重新下载，进行错误 ts 文件的第二次下载
        if((hasWaiting && file.status === TSStatus.Waiting) || (!hasWaiting && file.status === TSStatus.Error)) {
          addTaskTsCount(taskId)

          window.electron.ipcRenderer.startDownloadTS({
            url: file.url,
            filePath: file.path,
            taskId: taskId,
            // 一个m3u8中，ts文件名具有唯一性
            name: file.name
          })

          // 更新 TaskMap 
          file.status = TSStatus.Downloading

          // 更新数据库
          // db.downloadFiles.where({taskId: taskId, name: file.name}).modify({status: TSStatus.Downloading})

          break
        }
        
      }
    }

    // 侦听 是否要关闭程序
    window.electron.ipcRenderer.on('will-close', () => {
      // console.log('will-close', playTask)
      // 有症状播放的，或者正在下载的
      if((playTaskRef.current || taskCount > 0)) {
        Modal.confirm({
          title: '是否退出当前程序',
          content: '当前有课程正在下载或者播放，是否确定退出？',
          className: 'global-confirm-modal',
          onOk: () => {
            window.electron.ipcRenderer.exit()
          }
        })
      } else {
        window.electron.ipcRenderer.exit()
      }
    })

    // 侦听 ts 下载完成
    window.electron.ipcRenderer.on('download-ts-reply', async (data: any) => {
      // console.log('download ts :', data)

      const { taskId } = data
      const task = TaskMap[taskId]

      // 文件下载完成
      if(data.result.code === 0) {
        reduceTaskTsCount(taskId)

        // 更新 TaskMap 取到未下载的任务
        const { downloadCount } = task
        const files = task.files.filter(item => item.name !== data.name && item.status !== TSStatus.Done)

        // 判断是否下载完成
        if(files.length === 0) {
          // 下载完成
          // setTaskMap(old => {
          //   delete old[taskId]
          //   return {...old}
          // })
          delete TaskMap[taskId]
          taskCount = taskCount - 1;

          // 更新 task 数据库
          const newData = {
            downloadCount: downloadCount + 1, 
            status: TaskStatus.Done,
            completeTime: moment().format('YYYY-MM-DD hh:mm:ss')
        }
          db.downloadTasks.where({id: taskId}).modify(newData)
          // 更新 file 数据库
          db.downloadFiles.where({taskId: taskId, name: data.name}).modify({status: TSStatus.Done})

          // 开启新的 下载任务
          // 取第一个等待下载的任务进行下载
          const newTask = await db.downloadTasks.where('status').equals(TaskStatus.Waiting).first()
          if(newTask) {
            const newFiles = await db.downloadFiles.where({taskId: newTask.id!})
                                  .and(function(account){
                                    return account.status !== TSStatus.Done
                                  })
                                  .toArray()
            // console.log('files ==', files)
            addTask(newTask, newFiles)
          }

          //
          setTaskList(old => old.filter(item => item.id !== taskId))

          // 课程下载完成，课程文件写入 task.json 文件，以便于导入课程时使用
          // const taskJson: IDownloadDBTask = {...task, ...newData }
          const { files, ...taskData } = task
          window.electron.ipcRenderer.writeTask({...taskData, ...newData })

        } else {
          // 未下载完成
          // setTaskMap(old => {
          //   // 排除已经下载的
          //   task.files = files
          //   // ts 下载完成加 1
          //   task.downloadCount = downloadCount + 1
          //   old[taskId] = task
          //   return {...old}
          // })

          // 判断当前任务状态如果是暂停状态，则不继续下载
          if(task.status === TaskStatus.Downloading) {
            task.files = files
            task.downloadCount = downloadCount + 1
            TaskMap[taskId] = task

            // console.log('task ==', task)

            // 更新 task 数据库
            db.downloadTasks.where({id: taskId}).modify({downloadCount: downloadCount + 1})
            // 更新 file 数据库
            db.downloadFiles.where({taskId: taskId, name: data.name}).modify({status: TSStatus.Done})

            // 继续下载 ts
            downloadTS(TaskMap[taskId].files, taskId)
          }
          
        }

        
      } else {
        // 记录状态 下载失败的 ts ， 待正常的下载完成后，统一进行重新下载

        // 更新 setTaskMap 取到未下载的任务
        const files = TaskMap[data.taskId].files.map(item => item.name === data.name ? {...item, status: TSStatus.Error} : {...item})
        task.files = files
        TaskMap[taskId] = task

        // 更新 数据库
        db.downloadFiles.where({taskId: data.taskId, name: data.name}).modify({status: TSStatus.Error})

        // 开启新的下载
        downloadTS(TaskMap[taskId].files, taskId)
      }
      

    })

    // 获取主进程配置数据
    window.electron.ipcRenderer.getLocalConfig()
      .then(cfg => {
        // console.log('cfg ==', cfg)
        setConfig({...config, port: cfg.serverPort})
      })
    
    // 查询播放历史
    queryHistory()
    
  }, [])

  // console.log('playHistory =', playHistory)

  const globalContext = {
    user,
    loading: false,
    // TaskMap,
    taskList,
    playHistory,
    playTask, 
    config,
    setUserInfo,
    addTask,
    pauseTask,
    resumeTask,
    playCourse,
    updateCourse,
    deleteCourse,
  }




  return <GlobalContext.Provider value={globalContext} >{props.children}</GlobalContext.Provider>
}

export default GlobalProvider